package request

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"io"
	"net/url"
	"reflect"
	"strconv"
	"strings"
)

func BindJSONParams(ctx *gin.Context, obj interface{}) error {
	var requestBody []byte
	requestBody, _ = ctx.GetRawData()
	jsonBody := string(requestBody)
	fmt.Printf("%s", jsonBody)
	ctx.Request.Body = io.NopCloser(bytes.NewBuffer(requestBody))
	if err := ctx.ShouldBind(&obj); err != nil {
		jsonMap := make(map[string]interface{})
		if err = json.Unmarshal(requestBody, &jsonMap); err != nil {
			return err
		}
		// 遍历jsonMap
		for key, value := range jsonMap {
			if value == nil {
				continue
			}
			// 判断value是否为map
			if valueMap, ok := value.(map[string]interface{}); ok {
				//
				fmt.Printf("%v", valueMap)
			} else {
				err = _setTagValue(obj, key, value)
				if err != nil {
					return err
				}
			}
		}
	}
	return nil
}
func _setTagValue(obj any, tagName string, value any) error {
	objVal := reflect.ValueOf(obj)
	if objVal.Kind() != reflect.Ptr || objVal.Elem().Kind() != reflect.Struct {
		return fmt.Errorf("obj must be a pointer to a struct")
	}
	structVal := objVal.Elem()
	structTyp := structVal.Type()
	valueVal := reflect.ValueOf(value)
	//valueTyp := valueVal.Type()
	for i := 0; i < structTyp.NumField(); i++ {
		fieldTyp := structTyp.Field(i)
		tag := fieldTyp.Tag.Get("json")
		if tag == tagName {
			fieldVal := structVal.Field(i)
			// 检查字段是否可设置
			if !fieldVal.CanSet() {
				return fmt.Errorf("cannot set field %s", fieldTyp.Name)
			}
			// 处理指针字段
			if fieldTyp.Type.Kind() == reflect.Ptr {
				elemTyp := fieldTyp.Type.Elem()
				// 创建一个新的指针对象
				newPtr := reflect.New(elemTyp)
				// 尝试将 value 转换为 elemTyp 并设置
				if valueVal.Type().AssignableTo(elemTyp) {
					newPtr.Elem().Set(valueVal)
				} else if valueVal.Type().ConvertibleTo(elemTyp) {
					newPtr.Elem().Set(valueVal.Convert(elemTyp))
				} else {
					// 特殊处理：如果 value 是 string，尝试转换成数字
					if valueVal.Kind() == reflect.String {
						strVal := valueVal.String()
						switch elemTyp.Kind() {
						case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
							i64, err := strconv.ParseInt(strVal, 10, 64)
							if err != nil {
								return err
							}
							newPtr.Elem().Set(reflect.ValueOf(i64).Convert(elemTyp))
						case reflect.Float32, reflect.Float64:
							f64, err := strconv.ParseFloat(strVal, 64)
							if err != nil {
								return err
							}
							newPtr.Elem().Set(reflect.ValueOf(f64).Convert(elemTyp))
						default:
							return fmt.Errorf("cannot convert string to %v", elemTyp)
						}
					} else {
						return fmt.Errorf("cannot assign %v to %v", valueVal.Type(), elemTyp)
					}
				}
				// 设置字段值
				fieldVal.Set(newPtr)
			} else if fieldTyp.Type.Kind() == reflect.Slice {
				// 处理切片字段
				fmt.Printf("%v", value)
				newPtr := reflect.MakeSlice(fieldTyp.Type, 0, 0)
				for _, item := range valueVal.Interface().([]interface{}) {
					newItemPtr := reflect.New(fieldTyp.Type.Elem().Elem())
					for nodekey, nodevalue := range item.(map[string]interface{}) {
						err := _setTagValue(newItemPtr.Interface(), nodekey, nodevalue)
						if err != nil {
							continue
						}
					}
					newPtr = reflect.Append(newPtr, newItemPtr)
				}
				fieldVal.Set(newPtr)
			} else {
				// 非指针字段直接设置
				if valueVal.Type().AssignableTo(fieldTyp.Type) {
					fieldVal.Set(valueVal)
				} else if valueVal.Type().ConvertibleTo(fieldTyp.Type) {
					fieldVal.Set(valueVal.Convert(fieldTyp.Type))
				} else {
					return fmt.Errorf("cannot assign %v to %v", valueVal.Type(), fieldTyp.Type)
				}
			}
			return nil
		}
	}

	return fmt.Errorf("no field found with json tag: %s", tagName)
}
func BindFormParams(ctx *gin.Context) map[string]interface{} {
	request := ctx.Request
	form := request.Form
	params := map[string]interface{}{}
	_bindRequestForm(form, &params)
	_bindRequestUrl(request.RequestURI, &params)
	return params
}
func BindUrlParams(url string) map[string]interface{} {
	params := map[string]interface{}{}
	_bindRequestUrl(url, &params)
	return params
}
func _bindRequestForm(values url.Values, params *map[string]interface{}) {
	for key, values := range values {
		if strings.HasPrefix(key, "params[") && strings.HasSuffix(key, "]") {
			// 提取括号中的字段名：params[beginTime] -> beginTime
			fieldName := key[7 : len(key)-1]
			(*params)[fieldName] = values[0]
		}
	}
}
func _bindRequestUrl(urlStr string, params *map[string]interface{}) {
	//urlencoder
	decoded, err := url.QueryUnescape(urlStr)
	if err != nil {
		fmt.Println("解码失败:", err)
		return
	}
	fmt.Println("解码后:", decoded)
	values, err := url.ParseQuery(decoded)
	if err != nil {
		fmt.Println("解析失败:", err)
		return
	}
	_bindRequestForm(values, params)
}
